home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
gnu
/
vh-1_5.lha
/
vh-1.5
/
browse.c
next >
Wrap
C/C++ Source or Header
|
1993-05-11
|
34KB
|
1,453 lines
/*****************************************************************************
NAME
browse.c -- curses(3)-using display front end for vh database browser
SYNOPSIS
main(argc, argv) --- browser main sequence
int argc; char *argv[][];
DESCRIPTION
This module defines the main and browse loop for the vh browser;
all user-interface decisions are made here. Screen, keyboard and
mouse handling support may be found in screen.c.
AUTHORS
Written by Eric S. Raymond <eric@snark.thyrsus.com> for a UNIX
port of the 1.1 version of Raymond Gardner's MS-DOS browser, October
1991. Please see the source distribution's READ.ME for license
terms.
*****************************************************************************/
/*LINTLIBRARY*/
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>
#include <assert.h>
#ifdef ATT
#include <termio.h>
#endif /* ATT */
#include "screen.h"
#include "vh.h"
#ifndef CONST
#define const
#endif /* CONST */
#ifdef MSDOS
/* emulate Borland-style scrollbar */
#define SBARCH ACS_CKBOARD /* scrollbar character */
#define SBARTOPCH 30 /* scrollbar up arrow */
#define SBARBOTCH 31 /* scrollbar down arrow */
#else
/* approximate X-style scrollbar */
#define SBARCH ACS_VLINE /* scrollbar character */
#define SBARTOPCH ACS_TTEE /* scrollbar up arrow */
#define SBARBOTCH ACS_BTEE /* scrollbar down arrow */
#endif
#define SBARTHUMBCH ACS_BULLET /* scrollbar thumb character */
#ifdef A_COLOR
#define NORMPAIR 1
#define HILITEPAIR 2
#define SELPAIR 3
#define PROMPTPAIR 4
#define FKEYPAIR 5
#define SBARPAIR 6
#define SBARENDPAIR 7
#define SBTHUMBPAIR 8
#endif /* A_COLOR */
#define SUPPRESS 0
#define OPTIONAL 1
#define FORCED 2
#ifndef UNIX
#define erasechar() BS
#endif /* UNIX */
#define CUTFILE "%s.cut"
/*
* When paging forward or back, it helps the reader to page by a few less
* lines than the page depth, so a few of the old ones show to give context.
* This controls how many old lines will show.
*/
#define OVERLAP 4
/* dialogue/message window parameters */
#define DTOP 10
#define DLEFT 10
#define DHEIGHT 7
#define DWIDTH 42
/*******************************************************************
*
* All message texts declared here for internationalization purposes
*
******************************************************************/
#ifdef MSDOS
#define USAGE "usage: jargon [-cigms] [-b key] [srcname] [indexname]\n\
-c --- check textfile/index pair for consistency\n\
-i --- enable incremental-lookup and search\n\
-g --- generate new index from textfile\n\
-m --- force monochrome operation\n\
-s --- compensate for snowy EGA monitor\n\
-b --- write single entry specified by following key to stdout\n\
-r --- display random entry\n"
#define TBANNER "TAB-Index F1-help F10-exit"
#define IBANNER "TAB-Text F1-help F10-exit"
#else
#define USAGE "usage: jargon [-cigmr] [-b key] [srcname] [indexname]\n"
#define TBANNER "TAB-Index ^Q-help ^C-exit"
#define IBANNER "TAB-Text ^Q-help ^C-exit"
#endif
typedef struct
{
int left; /* left boundary of pushbutton */
int right; /* right boundary of pushbutton */
char cmd; /* command character associated with pushbutton */
}
strip;
static strip panel[] = {{0, 8, TAB}, {11, 17, CTL('Q')}, {21, 27, CTL('C')}};
#define PANELSTART (COLS - 1 - strlen((cf==&vhi) ? IBANNER : TBANNER) + 1)
#define NOREFS "No references on this page"
#define NOSRCH "No previous search"
#define CUTNOP "Can't open cut file"
#define CUTNOW "Cutting to jargon.cut..."
#define CUTDNE "Cutting to jargon.cut...Done"
#define BRSMES "Browsing %s...\n"
#define IDXMES "Generating index for %s...\n"
#define CHKMES "Performing consistency check for %s...\n"
/*
* These have to be declared static, not macros; we use the address of the
* current prompt as a mode indicator.
*/
const static char NOMESG[] = " ";
#ifndef POPUP
/* we want these fixed-length so the entry line looks good */
const static char SEARCH[] = "String search for: ";
const static char INSRCH[] = "Search proceeding: ";
const static char NOTFND[] = "Search failed: ";
const static char LOOKUP[] = "Looking up entry: ";
const static char LOOKING[] = "Lookup in progress:";
#else
/* the popup windows will get sized to these */
const static char SEARCH[] = "String search for";
const static char INSRCH[] = "Search proceeding";
const static char NOTFND[] = "Search failed";
const static char LOOKUP[] = "Looking up entry";
const static char LOOKING[] = "Lookup in progress";
const static char BDLOOK[] = "Lookup failed";
#endif /* POPUP */
const static char *help_screen[] =
{
" Jargon File Browser v. 1.5",
" Copyright 1991 by Raymond D. Gardner & Eric S. Raymond",
" All Rights Reserved; Free Redistribution Encouraged",
"",
" ^L redraw screen (Refresh)",
"",
" space page forward (PgDn)",
" ^U page back (PgUp)",
" ^N / ^P scroll forward / back (Down/Up Arrow)",
" ^A / ^O go to top / end of file (Home/End)",
"",
" ^J or ^M chase highlighted reference (Reference)",
" ^F / ^B next/previous reference (Right / Left Arrow)",
"",
" ^E lookup entry by name (Select)",
" ^S search for string (Find)",
" ^R repeat previous search (Shift-Find)",
#ifdef UNIX /* keypad() seems to disable recognition of ESC */
" ^H undo last search or lookup (Undo)",
#else
" ^H or ESC undo last search or lookup (Undo)",
#endif
"",
" ^I toggle between word list and text (Tab)",
" ^Y append selected entry to cut file (Print)",
"",
" Typing an entry name followed by Enter works like an ^E command.",
" Press any key to return to the browser.",
NULL,
};
/*******************************************************************
*
* Shared global data
*
******************************************************************/
static char *execname; /* name under which program was invoked */
static FILEINFO *cf; /* pointer to current fileinfo block */
/* highlights */
static chtype normattr, hiliteattr, selattr, promptattr, fkeyattr, sbarattr;
static chtype sbarendattr, sbthumbattr;
static char lasthit[LNSZ + 1]; /* last key searched for */
static char linbuf[LNSZ + 1]; /* line input scratch buffer */
#ifdef POPUP
static WINDOW *dwin; /* dialogue & message window */
#endif /* POPUP */
static bool incrsearch; /* do incremental search? */
/*******************************************************************
*
* Message and dialogue code
*
******************************************************************/
static void waitforit(requeue)
/* wait for keystroke or mouse click */
bool requeue;
{
int c;
#ifdef MOUSE
int hsy, hsx;
/* wait for keypress or button click */
while ((c = egetch()) == KEY_MOUSE)
if (A_BUTTON_CHANGED & mouse_status(&hsy, &hsx))
break;
#else
c = egetch();
#endif /* MOUSE */
if (requeue)
ungetch(c);
}
#if defined(POPUP) && defined(CURSES)
static void draw_box(win, ty,tx, by,bx)
/* draw a box on the screen using best possible forms chars */
WINDOW *win;
int ty, tx, by, bx;
{
int j;
mvwaddch(win, ty, tx, ACS_ULCORNER);
mvwaddch(win, by, bx, ACS_LRCORNER);
mvwaddch(win, by, tx, ACS_LLCORNER);
mvwaddch(win, ty, bx, ACS_URCORNER);
wmove(win, ty, tx+1);
for (j = tx + 1; j <= bx - 1; j++)
waddch(win, ACS_HLINE);
wmove(win, by, tx+1);
for (j = tx + 1; j <= bx - 1; j++)
waddch(win, ACS_HLINE);
for (j = ty + 1; j <= by - 1; j++)
{
wmove(win, j, tx);
waddch(win, ACS_VLINE);
}
for (j = ty + 1; j <= by - 1; j++)
{
wmove(win, j, bx);
waddch(win, ACS_VLINE);
}
wrefresh(win);
}
static char *get_dialogue(prompt)
/* get string from user, with prompts */
char *prompt;
{
static char buf[MAXCOLS + 1];
if (prompt == (char *)NULL)
{
delwin(dwin);
dwin = (WINDOW *)NULL;
}
else
{
/* create a dialogue window */
if (dwin == (WINDOW *)NULL)
dwin = newwin(DHEIGHT, DWIDTH, DTOP, DLEFT);
wclear(dwin);
draw_box(dwin, 0, 0, DHEIGHT-1, DWIDTH-1);
draw_box(dwin, 2, 1, DHEIGHT-3, DWIDTH-2);
wattron(dwin, A_BOLD);
mvwaddstr(dwin, 1, 10, prompt);
wattroff(dwin, A_BOLD);
echo();
mvwgetstr(dwin, 3, 3, buf);
noecho();
return(buf);
}
}
#endif /* defined(POPUP) && defined(CURSES) */
static void message(s)
/* write message to prompt line */
char *s;
{
#ifndef POPUP
attrset(promptattr);
mvaddstr(LINES-1, 0, s);
attrset(normattr);
refresh();
#else
WINDOW *mwin;
if (dwin)
{
mvwaddstr(dwin, 5, 10, NOMESG);
wattron(dwin, A_BOLD);
mvwaddstr(dwin, 5, 10, s);
wattroff(dwin, A_BOLD);
wrefresh(dwin);
}
else
{
mwin = newwin(3, strlen(s) + 2, DTOP, DLEFT);
wclear(mwin);
draw_box(mwin, 0, 0, 2, strlen(s) + 1);
wattron(mwin, A_BOLD);
mvwaddstr(mwin, 1, 1, s);
wattroff(mwin, A_BOLD);
wrefresh(mwin);
waitforit(TRUE);
overwrite(stdscr, mwin);
delwin(mwin);
touchline(DTOP, stdscr);
wrefresh(stdscr);
}
#endif /* POPUP */
}
/*******************************************************************
*
* The browser itself
*
******************************************************************/
static void uninitbrowse(doclear)
/* end the browse, either normally or due to signal */
bool doclear;
{
mouse_hide();
if (doclear)
{
clear();
refresh();
}
#ifdef CURSES
/* weird sex with the tty driver */
(void)resetterm();
(void)echo();
#ifndef OLDCURSES
(void)flushinp();
#endif /* OLDCURSES */
#endif /* CURSES */
(void)endwin();
exit(0);
}
static void paintselect(rp, attr)
/* turn highlight on a selection on or off */
region *rp; /* which to highlight */
chtype attr; /* attribute to use */
{
int x, y;
attrset(attr);
if (rp->yl == rp->yr)
{
move(rp->yl, rp->xl);
for (x = rp->xl; x <= rp->xr; x++)
addch(inch() & A_CHARTEXT);
}
else
{
int c, lastnsp;
/* don't highlight trailing spaces on line-wrapped references */
for (lastnsp = COLS - 1; lastnsp > 0; lastnsp--)
{
move(rp->yl, lastnsp);
if ((inch() & A_CHARTEXT) != ' ')
break;
}
/* write trailing-line part of highlight */
move(rp->yl, rp->xl);
for (x = rp->xl; x <= lastnsp; x++)
addch(inch() & A_CHARTEXT);
/* highlight everything *between* 1st and last lines in region */
for (y = rp->yl + 1; y < rp->yr; y++)
{
move(y, x);
for (x = 0; x < COLS - 1; x++)
addch(inch() & A_CHARTEXT);
}
/* don't highlight leading spaces on line-wrapped references */
for (x = 0; x <= COLS - 1; x++)
{
move(rp->yr, x);
if ((inch() & A_CHARTEXT) != ' ')
break;
}
/* write leading-line part of highlight */
move(rp->yr, x);
for (; x <= rp->xr; x++)
addch(inch() & A_CHARTEXT);
}
attrset(normattr);
}
static bool chase(x, y, isindex)
/* try to chase a link at this location */
int x, y;
bool isindex;
{
long pos; /* find target */
int dummy;
enqueue(cf); /* make sure we can un-chase it */
pos = iflink(x, y, &dummy, &dummy, isindex);
if (pos <= 0)
{
dequeue(cf);
return(FALSE);
}
else
{
if (isindex) /* if index, switch to text */
{
cf = vht;
cf->dsptoppos = cf->dspnextpos = NOWHERE;
}
cf->toppos = pos; /* set for new display */
return(TRUE);
}
}
static bool search(str, c)
/* search for given string in file */
char *str;
{
int i;
message(INSRCH);
enqueue(cf);
if (c)
cf->hitpos = ifind(cf->fp, cf->dspnextpos, c);
else
cf->hitpos = ffind(cf->fp, cf->dspnextpos, str);
if (cf->hitpos == NOWHERE)
{
message(NOTFND);
dequeue(cf);
return(FALSE);
}
else
{
/* else display hit on fourth line */
cf->toppos = cf->hitpos;
for (i = 0; i < OVERLAP; i++)
cf->toppos = getprevln(cf->fp, cf->toppos, linbuf);
if (str != lasthit)
(void) strcpy(lasthit, str);
return(TRUE);
}
}
static bool lookup(str, c)
/* search for given entry in file */
char *str, c;
{
long pos; /* find target */
enqueue(cf);
if (c)
pos = ilocate(c);
else
{
message(LOOKING);
pos = xlocate(str);
}
if (cf == &vhi) /* if index, switch to text */
{
cf = vht;
cf->dsptoppos = cf->dspnextpos = cf->endpos;
}
if (pos < 0)
{
cf->toppos = -pos; /* set for new display */
return(FALSE);
}
else
{
cf->toppos = pos; /* set for new display */
return(TRUE);
}
}
static daddr_t byname(prompt, str, c)
/* search or lookup given entry in file, depending on prompt value */
char *prompt, *str, c;
{
if (prompt == SEARCH)
return(search(str, c));
else
return(lookup(str, c));
}
/* entry buffer for lookup and search commands */
static char entrybuf[LNSZ + 1];
static int entrycnt = 0;
static void enterchar(c, prompt, row, col, maxcol)
/* accept a character into the entry buffer */
char c;
char *prompt;
int row, col;
int maxcol;
{
int es;
if (c == '\0')
{
entrybuf[entrycnt = 0] = '\0';
return;
}
es = col + strlen(prompt);
attrset(promptattr);
if (c == erasechar())
{
if (entrycnt > 0)
{
mvaddch(row, es + --entrycnt, ' ');
entrybuf[entrycnt] = '\0';
move(row, es + entrycnt);
ilocate(BS);
if (incrsearch)
dequeue(cf);
}
}
#ifdef CURSES
else if (c == killchar())
{
/* delete everything back to the end of the prompt */
while (entrycnt > 0)
{
mvaddch(row, es + --entrycnt, ' ');
entrybuf[entrycnt] = '\0';
move(row, es + entrycnt);
if (incrsearch)
dequeue(cf);
}
ilocate(DEL);
}
#endif /* CURSES */
else if (isprint(c))
{
mvaddstr(row, col, prompt);
if (es + entrycnt < maxcol
&& (!incrsearch || byname(prompt, (char *)NULL, c) != NOWHERE))
{
mvaddch(row, es + entrycnt, c);
entrybuf[entrycnt++] = c;
entrybuf[entrycnt] = '\0';
}
else if (c == '\0')
entrybuf[entrycnt = 0] = '\0';
else
beep();
}
attrset(normattr);
refresh();
}
static void cutentry(pos, fp)
/* send the text of the entry starting at pos to the gin file pointer */
daddr_t pos;
FILE *fp;
{
(void) fseek(vht->fp, pos, SEEK_SET);
/* always want first line */
(void) fgets(linbuf, LNSZ, vht->fp);
(void) fputs(linbuf, fp);
/* copy succeeding lines till we get to next entry */
while (fgets(linbuf, LNSZ, vht->fp) != (char *)NULL)
if (linbuf[0] == '=' || headword(linbuf))
break;
else
(void) fputs(linbuf, fp);
}
static char *nblanks(n)
/* blank-string return for fast fills; return up to 132 = MAXCOLS */
int n;
{
/* MAXCOLS+1 blanks */
const static char blanks[] = " ";
return(&blanks[sizeof(blanks) - 1 - n]);
}
static void browse(name, cok)
/* interactive browser loop */
char *name;
bool cok;
{
int i, c;
char **hp;
bool restore_select = FALSE;
FILE *cutfp;
int lightup = FORCED;
#ifdef MOUSE
int hsy, hsx, mstat; /* mouse hot spot coordinates */
bool thumbdrag = FALSE; /* are we in a thumbdrag? */
#endif /* MOUSE */
#ifndef POPUP
char *prompt = NOMESG;
#else
char *cp;
#endif /* POPUP */
#ifdef ATT
struct termio tty;
int saveintr;
#endif /* ATT */
if (!initbrowse(name))
exit(1);
cf = vht;
#ifdef UNIX
(void) signal(SIGINT,uninitbrowse);
(void) signal(SIGQUIT,uninitbrowse);
(void) signal(SIGTERM,uninitbrowse);
(void) signal(SIGIOT,uninitbrowse); /* for assert(3) */
#ifdef ATT
(void) ioctl(0, TCGETA, &tty);
saveintr = tty.c_cc[VINTR];
#endif /* ATT */
#endif /* UNIX */
(void) initscr();
setlastpage();
#ifdef A_COLOR
if (cok = (cok && has_colors()))
{
start_color();
init_pair(NORMPAIR, COLOR_WHITE, COLOR_BLUE);
init_pair(HILITEPAIR, COLOR_RED, COLOR_WHITE);
init_pair(SELPAIR, COLOR_YELLOW, COLOR_BLUE);
init_pair(PROMPTPAIR, COLOR_BLACK, COLOR_CYAN);
init_pair(FKEYPAIR, COLOR_RED, COLOR_CYAN);
init_pair(SBARPAIR, COLOR_WHITE, COLOR_BLACK);
init_pair(SBARENDPAIR, COLOR_BLUE, COLOR_WHITE);
init_pair(SBTHUMBPAIR, COLOR_BLUE, COLOR_BLACK);
}
mouse_color(cok);
normattr = cok ? (COLOR_PAIR(NORMPAIR) | A_BOLD) : A_NORMAL;
hiliteattr = cok ? COLOR_PAIR(HILITEPAIR) : A_REVERSE;
selattr = cok ? (COLOR_PAIR(SELPAIR) | A_BOLD) : A_BOLD;
promptattr = cok ? COLOR_PAIR(PROMPTPAIR) : A_REVERSE;
fkeyattr = cok ? COLOR_PAIR(FKEYPAIR) : A_BOLD;
#ifndef MSDOS
sbarendattr = sbthumbattr =
sbarattr = cok ? COLOR_PAIR(SBARPAIR) : A_NORMAL;
#else
sbarattr = cok ? COLOR_PAIR(SBARPAIR) : A_REVERSE;
sbarendattr = cok ? (COLOR_PAIR(SBARENDPAIR) | A_BOLD) : A_REVERSE;
sbthumbattr = cok ? (COLOR_PAIR(SBTHUMBPAIR) | A_BOLD) : A_NORMAL;
#endif
#else
normattr = A_NORMAL;
hiliteattr = A_REVERSE;
selattr = A_BOLD;
promptattr = A_REVERSE;
fkeyattr = A_BOLD;
sbarendattr = sbthumbattr =
sbarattr = A_NORMAL;
#ifdef MSDOS
sbarattr = A_REVERSE;
sbarendattr = A_REVERSE;
sbthumbattr = A_NORMAL;
#endif /* MSDOS */
#endif /* A_COLOR */
mouse_init();
#ifdef MOUSE
mouse_move(LINES - 1, COLS - 1);
#endif /* MOUSE */
#ifdef CURSES
(void)saveterm();
(void)nonl();
(void)raw();
(void)noecho();
#ifndef OLDCURSES
(void)keypad(stdscr, TRUE);
#endif /* BSD */
#endif /* CURSES */
#ifdef ATT
(void) ioctl(0, TCGETA, &tty);
tty.c_cc[VINTR] = saveintr;
tty.c_iflag |= BRKINT;
tty.c_iflag &=~ IGNBRK;
tty.c_lflag |= ISIG;
(void) ioctl(0, TCSETA, &tty);
#endif /* ATT */
lasthit[0] = '\0';
for (c = KEY_REFRESH; c != CTL('C') && c != KEY_EXIT; c = egetch())
{
#ifdef DEBUG
if (isprint(c))
(void) fprintf(stderr, "command: %c\n", c);
else if (iscntrl(c))
(void) fprintf(stderr, "command: ^%c\n", c + '@');
else if (c >= 0x80 & c <= 0x9f)
(void) fprintf(stderr, "command: M-^%c\n", (c &~ 0x80) + '@');
else if (c >= 0x80)
(void) fprintf(stderr, "command: M-%c\n", c &~ 0x80);
else
(void) fprintf(stderr, "command: 0x%02x\n", c);
#endif /* DEBUG */
switch(c)
{
#ifdef MSDOS
case KEY_F(10):
(void) ungetch(KEY_EXIT);
break;
#endif /* MSDOS */
#ifndef OLDCURSES
case KEY_HELP: /* go to help screen */
#endif /* OLDCURSES */
case CTL('Q'):
#ifdef MSDOS
case KEY_F(1):
#endif /* MSDOS */
restore_select = TRUE;
i = 0;
for (hp = help_screen; *hp; hp++)
{
mvaddstr(i++, 0, *hp);
addstr(nblanks(COLS - strlen(*hp)));
}
refresh();
cf->dsptoppos = NOWHERE;
waitforit(FALSE);
/* FALL THROUGH */
#ifndef OLDCURSES
case KEY_REFRESH: /* redraw screen */
#endif /* OLDCURSES */
case CTL('L'):
restore_select = TRUE;
#ifdef CURSES
clearok(stdscr, TRUE);
#endif /* CURSES */
break;
case SP:
restore_select = FALSE;
#ifndef POPUP
if (prompt != NOMESG)
goto medialspace;
/* FALL THROUGH */
#endif /* POPUP */
#ifndef OLDCURSES
case KEY_NPAGE: /* page forward */
#endif /* OLDCURSES */
pagefwd:
enqueue(cf);
restore_select = FALSE;
for (i = 0; i < LINES - OVERLAP; i++)
{
if (cf->toppos == cf->lastpagetoppos)
break;
cf->toppos = getnextln(cf->fp, cf->toppos, linbuf);
}
if (cf->sel.xl != NOPLACE)
{
cf->sel.yl -= i; cf->sel.yr -= i;
if (!(restore_select = (cf->sel.yl >= 0)))
cf->sel.xl = NOPLACE;
}
break;
#ifndef OLDCURSES
case KEY_PPAGE: /* page back */
#endif /* OLDCURSES */
case CTL('U'):
pagebak:
enqueue(cf);
restore_select = FALSE;
for (i = 0; i < LINES - OVERLAP; i++)
{
if (cf->toppos == 0)
break;
cf->toppos = getprevln(cf->fp, cf->toppos, linbuf);
}
if (cf->sel.xl != NOPLACE)
{
cf->sel.yl += i; cf->sel.yr += i;
if (!(restore_select = (cf->sel.yr < LINES - 1)))
cf->sel.xl = NOPLACE;
}
break;
#ifndef OLDCURSES
case KEY_UP:
#endif /* OLDCURSES */
case CTL('N'):
linebak:
restore_select = FALSE;
if (cf->toppos)
{
cf->toppos = getprevln(cf->fp, cf->toppos, linbuf);
if (cf->sel.xl != NOPLACE)
{
cf->sel.yl++; cf->sel.yr++;
if (!(restore_select = (cf->sel.yr < LINES - 1)))
cf->sel.xl = NOPLACE;
}
}
break;
#ifndef OLDCURSES
case KEY_DOWN:
#endif /* OLDCURSES */
case CTL('P'):
linefwd:
restore_select = FALSE;
if (cf->toppos < cf->lastpagetoppos)
{
cf->toppos = getnextln(cf->fp, cf->toppos, linbuf);
if (cf->sel.xl != NOPLACE)
{
cf->sel.yl--; cf->sel.yr--;
if (!(restore_select = (cf->sel.yl >= 0)))
cf->sel.xl = NOPLACE;
}
}
break;
#ifndef OLDCURSES
case KEY_ENTER: /* accept keyboard input */
#endif /* OLDCURSES */
case CTL('J'):
case CTL('M'):
lightup = FORCED;
#ifndef POPUP
restore_select = FALSE;
if (prompt == SEARCH || prompt == LOOKUP)
{
if (!incrsearch && byname(prompt, entrybuf, '\0') == NOWHERE)
beep();
enterchar('\0', LOOKUP, LINES - 1, 0, PANELSTART);
prompt = NOMESG;
break;
}
/* nothing in prompt buffer, no search active: FALL THROUGH */
#endif /* POPUP */
#ifndef OLDCURSES
case KEY_REFERENCE: /* chase reference */
#endif /* OLDCURSES */
restore_select = FALSE;
if (cf->sel.xl == NOPLACE) /* any link? */
{
message(NOREFS);
continue;
}
else
(void) chase(cf->sel.xl, cf->sel.yl, cf == &vhi);
break;
#ifndef OLDCURSES
case KEY_RIGHT: /* next reference */
#endif /* OLDCURSES */
case CTL('F'):
restore_select = FALSE;
if (cf->sel.xl == NOPLACE)
message(NOREFS);
else
{
paintselect(&cf->sel, (cf == &vhi) ? normattr : selattr);
cf->sel = findnextsel(cf->sel.xl, cf->sel.yl, cf == &vhi);
paintselect(&cf->sel, hiliteattr);
}
refresh();
continue;
#ifndef OLDCURSES
case KEY_LEFT: /* previous reference */
#endif /* OLDCURSES */
case CTL('B'):
restore_select = FALSE;
if (cf->sel.xl == NOPLACE)
message(NOREFS);
else
{
paintselect(&cf->sel, (cf == &vhi) ? normattr : selattr);
/*
* The -1 offset on xsel is important. It insures that
* when findprevsel() starts looking for a previous
* tag, it doesn't find the current one again.
*/
cf->sel = findprevsel(cf->sel.xl-1, cf->sel.yl, cf == &vhi);
paintselect(&cf->sel, hiliteattr);
}
refresh();
continue;
#ifndef OLDCURSES
case KEY_FIND: /* search for string */
#endif /* OLDCURSES */
case CTL('S'):
restore_select = FALSE;
#ifndef POPUP
prompt = SEARCH;
#else
if (cp = get_dialogue(SEARCH))
if (search(cp, '\0') != NOWHERE)
{
get_dialogue((char *)NULL);
break;
}
else
continue;
#endif /* POPUP */
break;
#ifndef OLDCURSES
case KEY_SFIND: /* search for last string again */
#endif /* OLDCURSES */
case CTL('R'):
restore_select = FALSE;
if (lasthit[0] == '\0')
{
message(NOSRCH);
continue;
}
else
#ifdef POPUP
(void) search(lasthit, '\0');
#else
{
prompt = SEARCH;
(void) strcpy(entrybuf, lasthit);
entrycnt = strlen(lasthit);
(void) ungetch(CTL('J'));
}
#endif /* POPUP */
break;
#ifndef OLDCURSES
case KEY_SELECT: /* search for entry */
#endif /* OLDCURSES */
case CTL('E'):
lookfor:
restore_select = FALSE;
#ifndef POPUP
prompt = LOOKUP;
#else
if (cp = get_dialogue(LOOKUP))
{
if (lookup(cp, '\0') == NOWHERE)
beep();
get_dialogue((char *)NULL);
break;
}
#endif /* POPUP */
break;
#ifndef OLDCURSES
case KEY_HOME: /* go to beginning of file */
case KEY_BEG:
#endif /* OLDCURSES */
case CTL('A'):
enqueue(cf);
restore_select = FALSE;
cf->toppos = 0;
break;
#ifndef OLDCURSES
case KEY_END: /* go to end of file */
#endif /* OLDCURSES */
case CTL('O'):
enqueue(cf);
restore_select = FALSE;
cf->toppos = cf->lastpagetoppos;
break;
case BS: /* this is context-sensitive */
#ifndef POPUP
if (prompt != NOMESG)
goto medialspace;
/* FALL THROUGH */
#endif /* POPUP */
#ifndef OLDCURSES
case KEY_UNDO: /* backtrack into the location stack */
#endif /* OLDCURSES */
case ESC:
restore_select = TRUE;
dequeue(cf);
break;
case TAB: /* toggle between text and index */
restore_select = TRUE;
vhi.dsptoppos = vht->dsptoppos = NOWHERE;
if (cf == vht)
cf = &vhi;
else
cf = vht;
break;
#ifndef OLDCURSES
case KEY_PRINT: /* append selected entry to file */
#endif /* OLDCURSES */
case CTL('Y'):
restore_select = FALSE;
(void) sprintf(linbuf, CUTFILE, execname);
if (cf->sel.xl == NOPLACE)
{
message(NOREFS);
continue;
}
else if ((cutfp = fopen(linbuf, "a")) == (FILE *)NULL)
{
message(CUTNOP);
continue;
}
else
{
long pos; /* find target */
int dummy;
message(CUTNOW);
pos = iflink(cf->sel.xl, cf->sel.yl, &dummy,&dummy, cf == &vhi);
if (pos >= 0) /* how can this fail? */
cutentry(pos, cutfp);
(void) fclose(cutfp);
message(CUTDNE);
continue;
}
break;
#ifdef MOUSE
/*
* Note: we treat a single-button mouse as having the left
* button only.
*
* The mouse_status() function should return the key-status defines
* implied below when appropriate. It should return the zero-origin
* mouse hotspot coordinates at character-cell resolution, with
* CMDLINE and THUMBCOL as special values designating the command
* line and thumb column respectively (on character displays these
* would be LINES - 1 and COLS - 1 respectively).
*/
case KEY_MOUSE: /* mouse gesture has occurred */
mstat = mouse_status(&hsy, &hsx);
#ifndef POPUP
hsy = (hsy == LINES - 1) ? CMDLINE : hsy;
#endif /* POPUP */
switch(mstat)
{
case BUTTON1_PRESSED: /* left button down; chase link, else page */
restore_select = FALSE;
if (hsy == CMDLINE) /* clicked on entry line */
{
hsx -= PANELSTART;
for (i = 0; i < sizeof(panel) / sizeof(strip); i++)
if (hsx >= panel[i].left && hsx <= panel[i].right)
(void) ungetch(panel[i].cmd);
continue;
}
else if (hsx == THUMBCOL) /* click in thumb column */
{
if (hsy == 0) /* clicked top of bar */
goto linebak;
else if (hsy == LASTLINE) /* clicked bottom of bar */
goto linefwd;
else if (hsy < cf->ythumb) /* clicked above thumb */
goto pagebak;
else if (hsy > cf->ythumb) /* clicked below thumb */
goto pagefwd;
else /* clicked on the thumb */
thumbdrag = TRUE;
}
else if (!chase(hsx, hsy, cf == &vhi))
goto pagefwd; /* click in text somewhere */
break;
case BUTTON1_RELEASED: /* left button up */
restore_select = FALSE;
if (thumbdrag && 0 < hsy && hsy < LASTLINE)
{
cf->toppos = /* compute new position */
cf->lastpagetoppos *
(hsy - 1) / (LASTLINE - 2);
assert(0 <= cf->toppos &&
cf->toppos <= cf->lastpagetoppos);
/* ensure on line boundary */
if (0 < cf->toppos && cf->toppos < cf->lastpagetoppos)
cf->toppos = getnextln(cf->fp, cf->toppos, linbuf);
}
thumbdrag = FALSE;
break;
case BUTTON3_PRESSED: /* right button down; backtrack */
restore_select = TRUE;
dequeue(cf);
break;
case BUTTON3_RELEASED: /* right button up */
/* reserved for future expansion */
break;
}
break;
#endif /* MOUSE */
default:
#ifdef POPUP
if (isprint(c))
{
(void) ungetch(c);
goto lookfor;
}
#else
medialspace:
restore_select = FALSE;
if (prompt == NOMESG)
{
ungetch(c);
goto lookfor;
}
enterchar(c, prompt, LINES - 1, 0, PANELSTART);
#endif /* POPUP */
lightup = SUPPRESS;
}
#ifndef POPUP
/* regenerate prompt */
attrset(promptattr);
move(LINES - 1, 0);
addstr(prompt);
addstr(entrybuf);
addstr(nblanks(PANELSTART - strlen(prompt) - strlen(entrybuf)));
mvaddstr(LINES - 1, PANELSTART, (cf == &vhi) ? IBANNER : TBANNER);
attrset(normattr);
#endif /* POPUP */
if (cf->toppos != cf->dsptoppos)
{
int i;
long newpos = cf->toppos;
#ifdef DEBUG
(void) fprintf(stderr,
"screen update triggered, toppos = %ld\n",
cf->toppos);
#endif /* DEBUG */
attrset(normattr);
for (i = 0; i <= LASTLINE; i++)
if ((newpos = getnextln(cf->fp, newpos, linbuf)) != NOWHERE)
{
mvaddstr(i, 0, linbuf);
/*
* This is actually faster, and creates less
* flicker, than clearing the screen.
*/
addstr(nblanks(COLS - strlen(linbuf)));
}
cf->dspnextpos = ftell(cf->fp);
#ifdef SCROLLBAR
/*
* Generate the scroll bar. Yes, we really do want the denominator
* to be lastpagetoppos and not endpos. This means the thumb only
* bottoms out if we're really at the end.
*/
cf->ythumb = 1 + cf->toppos * (LASTLINE - 2) / cf->lastpagetoppos;
assert(0 < cf->ythumb && cf->ythumb < LASTLINE);
mvaddch(0, COLS, SBARTOPCH | sbarendattr);
for (i = 1; i < LASTLINE; i++) /* set up scrollbar */
mvaddch(i, COLS, SBARCH | sbarattr);
mvaddch(LASTLINE, COLS, SBARBOTCH | sbarendattr);
mvaddch(cf->ythumb, COLS, SBARTHUMBCH | sbthumbattr);
#endif /* SCROLLBAR */
}
/*
* This has to be done whether or not lightup is going to happen.
* Otherwise, a following command may enqueue a bogus selection
* box as part of state.
*/
cf->sel = findnextsel(0, -1, cf == &vhi);
if (lightup == SUPPRESS)
lightup = OPTIONAL;
else
{
if (incrsearch)
(void) byname(prompt, (char *)NULL, DEL);
if (lightup == FORCED || cf->toppos != cf->dsptoppos)
{
lightup = OPTIONAL;
/* highlight the current select, if any */
if (restore_select && cf->sel.xl != NOPLACE)
paintselect(&cf->sel, hiliteattr); /* restore existing select */
else
{
/* highlight the first selection, if there is one */
if (cf->sel.xl != NOPLACE)
paintselect(&cf->sel, hiliteattr);
}
/* if in text, boldface all potential selects */
if (!(cf == &vhi) && cf->sel.xl != NOPLACE)
{
region hibox;
#ifdef DEBUG
(void) fprintf(stderr,
"current: x = %2d, y = %2d, pos = %ld.\n",
cf->sel.xl, cf->sel.yl, cf->toppos);
#endif /* DEBUG */
hibox.xl = cf->sel.xl;
hibox.yl = cf->sel.yl;
for (;;)
{
hibox = findnextsel(hibox.xl, hibox.yl, cf == &vhi);
#ifdef DEBUG
(void) fprintf(stderr,
"hibox: x = %2d, y = %2d.\n",
hibox.xl, hibox.yl);
#endif /* DEBUG */
if (hibox.xl == cf->sel.xl && hibox.yl == cf->sel.yl)
break;
paintselect(&hibox, selattr);
}
}
}
}
move(LINES - 1, 0);
cf->dsptoppos = cf->toppos;
refresh();
}
uninitbrowse(TRUE);
}
#ifdef MSDOS
static char *basename(s)
/* isolate base name of fully qualified filename (modifies the name passed!) */
char *s;
{
char *p;
p = strrchr(s, '.'); /* find rightmost dot */
if ( strchr(p, '\\') ) /* if a \ comes after it, find string end */
p = strchr(p, 0);
*p = 0; /* terminate at last dot after a \ (if any)*/
if ( (p = strrchr(s, '\\')) == NULL ) /* find last \ (if any) */
p = s; /* take whole string if no \ */
else
++p; /* else take string after \ */
strlwr(p);
return p;
}
#else
#define basename(x) x /* don't need to strip argv[0] under UNIX */
#endif /* MSDOS */
/*******************************************************************
*
* Main sequence
*
******************************************************************/
main(argc, argv)
int argc;
char **argv;
{
char *dbname, *batchkey = NULL;
int i;
bool doindex = FALSE, docheck = FALSE, dofilter = FALSE;
bool forcemono = FALSE, atrandom = FALSE;
execname = argv[0];
while ((++argv, --argc) && *argv[0] == '-')
for (i = 1; argv[0][i]; i++)
switch(argv[0][i])
{
case 'b':
batchkey = argv[1];
break;
case 'c':
docheck = TRUE;
break;
case 'f':
dofilter = TRUE;
break;
case 'g':
doindex = TRUE;
break;
case 'i':
incrsearch = TRUE;
break;
case 'm':
forcemono = TRUE;
break;
case 'r':
atrandom = TRUE;
break;
#ifdef __TURBOC__
case 's':
{ /* if CGA that snows: */
extern bool has_snowy_CGA;
has_snowy_CGA = TRUE;
}
break;
#endif /* __TURBOC__ */
default:
(void) fprintf(stderr, USAGE);
exit(1);
}
#ifdef DEBUG
(void) freopen("ERRLOG", "w", stderr);
#endif /* DEBUG */
/*
* User specified a batch-retrieval option.
* OK, snarf the keyword from the next argument.
*/
if (batchkey)
++argv, --argc;
dbname = argc ? argv[0] : basename(execname);
if (!doindex && !docheck && !atrandom && !dofilter
&& batchkey == (char *)NULL)
{
(void) printf(BRSMES, dbname);
browse(dbname, !forcemono);
}
if (doindex)
{
(void) printf(IDXMES, dbname);
if (argc)
mkindex(argc, argv);
else
mkindex(1, &dbname);
}
if (docheck)
{
(void) printf(CHKMES, dbname);
chkindex(dbname);
}
if (batchkey)
{
daddr_t pos;
if (!initbrowse(dbname))
exit(1);
if ((pos = xlocate(batchkey)) >= 0)
cutentry(pos, stdout);
}
if (dofilter)
{
daddr_t pos;
char batchkey[81];
if (!initbrowse(dbname))
exit(1);
while (fgets(batchkey, sizeof(batchkey) - 1, stdin) != (char *)NULL)
{
char *ep = &batchkey[strlen(batchkey) - 1];
if (*ep == '\n')
{
*ep = '\0';
if (*--ep == '\r')
*ep = '\0';
}
if ((pos = xlocate(batchkey)) >= 0)
cutentry(pos, stdout);
}
}
if (atrandom)
{
daddr_t pos;
if (!initbrowse(dbname))
exit(1);
if ((pos = jrandom()) >= 0)
cutentry(pos, stdout);
}
exit(0);
}
/* browse.c ends here */